package com.twu.biblioteca.util;

import com.twu.biblioteca.BibliotecaApp;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by sgreweni on 30.07.14.
 */
public enum CommandOption {
    Login("1", "Login", MenuAvailability.LOGGEDOUT, new LoginCommand()),
    Logout("1", "Logout", MenuAvailability.LOGGEDIN, new LogoutCommand()),
    ListBooks("2", "List available books", MenuAvailability.BOTH, new ListBooksCommand()),
    ListMovies("3", "List available movies", MenuAvailability.BOTH, new ListMoviesCommand()),
    CheckoutBook("4", "Checkout book", MenuAvailability.LOGGEDIN, new CheckoutBookCommand()),
    ReturnBook("5", "Return book", MenuAvailability.LOGGEDIN, new ReturnBookCommand()),
    CheckoutMovie("6", "Checkout movie", MenuAvailability.LOGGEDIN, new CheckoutMovieCommand()),
    ReturnMovie("7", "Return movie", MenuAvailability.LOGGEDIN, new ReturnMovieCommand()),
    SHOWINFO("8", "Show user information", MenuAvailability.LOGGEDIN, new ShowInfoCommand()),
    Quit("q", "Quit", MenuAvailability.BOTH, new QuitCommand());


    private final String selectionKey;
    private final String description;
    private final MenuAvailability availability;
    private final Command command;

    private CommandOption(String selectionKey, String description, MenuAvailability availability, Command command) {
        this.selectionKey = selectionKey;
        this.description = description;
        this.availability = availability;
        this.command = command;
    }

    public static Optional<CommandOption> getFromKey(String key, boolean loggedIn) {
        List<CommandOption> commandOptions = Arrays.asList(values());
        Stream<CommandOption> filter = commandOptions.stream().filter(commandOption -> {
            if (commandOption.selectionKey.equals(key)) {
                if(loggedIn && commandOption.availability!=MenuAvailability.LOGGEDOUT){
                    return true;
                }
                if(!loggedIn && commandOption.availability!=MenuAvailability.LOGGEDIN){
                    return true;
                }
            }
            return false;
        });
        return filter.findFirst();
    }

    @Override
    public String toString() {
        return this.selectionKey+") "+this.description;
    }

    public static Collection<CommandOption> getValues(boolean loggedIn){
        Collection<CommandOption> options;
        if(loggedIn){
            options = Arrays.asList(values()).stream().filter(commandOption -> commandOption.availability != MenuAvailability.LOGGEDOUT).collect(Collectors.toCollection(() -> new LinkedList<>()));
        } else {
            options = Arrays.asList(values()).stream().filter(commandOption -> commandOption.availability != MenuAvailability.LOGGEDIN).collect(Collectors.toCollection(() -> new LinkedList<>()));
        }
    return options;
    }

    public Command getCommand() {
        return command;
    }
}

class ListBooksCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.listAvailableBooks();
    }
}

class ListMoviesCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.listAvailableMovies();
    }
}

class CheckoutBookCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.checkOutBook();
    }
}

class ReturnBookCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.returnBook();
    }
}

class CheckoutMovieCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.checkOutMovie();
    }
}

class ReturnMovieCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.returnMovie();
    }
}

class QuitCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.quit();
    }
}

class LoginCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.login();
    }
}

class LogoutCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.logout();
    }
}

class ShowInfoCommand implements Command {

    @Override
    public void execute(BibliotecaApp app) {
        app.showInfo();
    }
}